package com.nkym.wypan.service.impl;/*
 * @ClassName RecycleServiceImpl
 * @Desc TODO
 * @Author 19637
 * @Date 2023/7/7 16:59
 * @Version 1.0
 */

import java.util.List;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nkym.wypan.enums.FileDelFlag;
import com.nkym.wypan.enums.FolderFlag;
import com.nkym.wypan.enums.ResponseStatus;
import com.nkym.wypan.event.FileDeleteEvent;
import com.nkym.wypan.exception.BusinessException;
import com.nkym.wypan.model.context.recycle.RecycleFileDeleteContext;
import com.nkym.wypan.model.context.recycle.RecyclePageContext;
import com.nkym.wypan.model.context.recycle.RestoreContext;
import com.nkym.wypan.model.entity.UserFile;
import com.nkym.wypan.model.resp.recycle.RecycleListVo;
import com.nkym.wypan.model.resp.recycle.RecyclePageVo;
import com.nkym.wypan.service.RecycleService;
import com.nkym.wypan.service.UserFileService;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class RecycleServiceImpl implements RecycleService, ApplicationContextAware {
    @Autowired
    private UserFileService userFileService;
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 校验权限
     * 校验重复名字
     * 恢复文件
     * 后置操作
     *
     * @param restoreContext 文件恢复上下文
     */
    @Override
    public void restore(RestoreContext restoreContext) {
        //得到需要恢复的文件列表
        List<UserFile> userFileList = checkRestorePermission(restoreContext);
        checkDuplicatedName(restoreContext, userFileList);
        doRestore(restoreContext, userFileList);

    }


    /**
     * @param context
     * @return
     */
    @Override
    public RecycleListVo pageList(RecyclePageContext context) {
     Long userId = context.getUserId();
     Integer offset = context.getOffset();
     Integer size = context.getSize();
     Integer delFlag = context.getDelFlag();

        List<UserFile> userFileList = userFileService.recyclePageList(context);
        List<RecyclePageVo> recyclePageVoList = Lists.newArrayList();
        long count = userFileService.count(new LambdaQueryWrapper<UserFile>()
                .eq(UserFile::getUserId, userId)
                .eq(UserFile::getDelFlag, delFlag)
        );
        userFileList.forEach(r -> recyclePageVoList.add(cover2RecyclePageVo(r)));
        RecycleListVo listVo = new RecycleListVo();
        listVo.setQueryRecycleVos(recyclePageVoList);
        listVo.setTotalPage(count);
        return listVo;
    }

    /**
     * 删除文件
     * ---> 1、校验权限
     * 2、删除文件
     *
     * @param context
     */
    @Override
    public void deleteFile(RecycleFileDeleteContext context) {
        List<UserFile> userFileList = checkDeletePermission(context);
        List<UserFile> userFiles = doDelete(context, userFileList);
        doPostProcessor(userFiles);
    }

    private void doPostProcessor(List<UserFile> userFiles) {
        publishDeleteEvent(userFiles);
    }

    private void publishDeleteEvent(List<UserFile> userFileList) {
        FileDeleteEvent event = new FileDeleteEvent();
        event.setUserFileList(userFileList);
        applicationContext.publishEvent(event);

    }

    private List<UserFile> doDelete(RecycleFileDeleteContext context, List<UserFile> userFileList) {
        List<UserFile> allNeedDeleteFile = Lists.newArrayList();
        for (UserFile userFile : userFileList) {
            if (FolderFlag.YES.getCode().equals(userFile.getFolderFlag())) {
                findAllDeleteFile(allNeedDeleteFile, userFile);
            }
        }
        allNeedDeleteFile.addAll(userFileList);
        allNeedDeleteFile = allNeedDeleteFile.stream().map(r -> {
            r.setDelFlag(FileDelFlag.DEL.getCode());
            r.setUpdateTime(new Date());
            return r;
        }).collect(Collectors.toList());
        boolean b = userFileService.updateBatchById(allNeedDeleteFile);
        if (!b) {
            log.error("文件删除失败");
            throw new BusinessException("文件删除失败");
        }
        return allNeedDeleteFile;
    }

    /**
     * 找到要删除文件的所有子文件一并删除
     *
     * @param allNeedDeleteFile
     * @param userFile
     */
    private void findAllDeleteFile(List<UserFile> allNeedDeleteFile, UserFile userFile) {
        if (userFile == null || !FolderFlag.YES.getCode().equals(userFile.getFolderFlag())) {
            return;
        }
        //当前目录下的所有文件
        List<UserFile> fileList = userFileService.list(new LambdaQueryWrapper<UserFile>()
                .eq(UserFile::getParentId, userFile.getFileId())
                .ne(UserFile::getDelFlag, FileDelFlag.DEL.getCode()));
        //递归查找
        for (UserFile u : fileList) {
            allNeedDeleteFile.add(u);
            if (FolderFlag.YES.getCode().equals(u.getFolderFlag())) {
                findAllDeleteFile(allNeedDeleteFile, u);
            }
        }
    }

    private List<UserFile> checkDeletePermission(RecycleFileDeleteContext context) {
        List<Long> fileIds = context.getFileIds();
        Long userId = context.getUserId();
        List<UserFile> userFileList = userFileService.list(new LambdaQueryWrapper<UserFile>()
                .eq(UserFile::getUserId, userId)
                .eq(UserFile::getDelFlag, FileDelFlag.RECYCLE.getCode())
                .in(UserFile::getFileId, fileIds)
        );
        if (userFileList == null || userFileList.isEmpty()) {
            log.error("文件删除失败，文件删除非本人进行，非法操作");
            throw new BusinessException(ResponseStatus.ILLEGAL_OPERATION);
        }
        if (fileIds.size() != userFileList.size()) {
            log.error("文件删除失败，文件删除非本人进行，非法操作");
            throw new BusinessException(ResponseStatus.ILLEGAL_OPERATION);
        }
        return userFileList;
    }

    /**
     * ---------------------------------------private-----------------------------------------------------
     */
    /**
     * 转换为RecyclePageVo
     *
     * @param userFile
     * @return
     */
    private RecyclePageVo cover2RecyclePageVo(UserFile userFile) {
        RecyclePageVo recyclePageVo = new RecyclePageVo();
        recyclePageVo.setFileId(userFile.getFileId());
        recyclePageVo.setFilename(userFile.getFilename());
        recyclePageVo.setFileSize(userFile.getFileSize());
        recyclePageVo.setFolderFlag(userFile.getFolderFlag());
        recyclePageVo.setFileType(userFile.getFileType());
        recyclePageVo.setUpdateTime(userFile.getUpdateTime());
        return recyclePageVo;
    }

    /**
     * 还原文件时检查是否存在重复命名的文件
     *
     * @param restoreContext
     * @param userFileList
     */
    private void checkDuplicatedName(RestoreContext restoreContext, List<UserFile> userFileList) {
        Long userId = restoreContext.getUserId();
        //找到所在目录
        List<Long> parentIdList = userFileList.stream().map(UserFile::getParentId).distinct().collect(Collectors.toList());
        Map<Long, Set<String>> map = new HashMap<>();
        //查看是否有同名文件
        parentIdList.forEach(pid -> {
            List<UserFile> list = userFileService.list(new LambdaQueryWrapper<UserFile>()
                    .eq(UserFile::getUserId, userId)
                    .eq(UserFile::getParentId, pid)
                    .eq(UserFile::getDelFlag, FileDelFlag.NORMAL.getCode()));
            if (list != null) {
                Set<String> filenameSet = list.stream().map(UserFile::getFilename).collect(Collectors.toSet());
                map.put(pid, filenameSet);
            }
        });
        for (UserFile userFile : userFileList) {
            Long parentId = userFile.getParentId();
            Set<String> filenameSet = map.get(parentId);
            if (filenameSet == null) continue;
            String filename = userFile.getFilename();
            if (filenameSet.contains(filename)) {
                //重命名文件
                userFile.setFilename(filename + UUID.randomUUID().toString().substring(0, 10) + System.currentTimeMillis());
            }
        }
    }

    /**
     * 恢复文件
     *
     * @param restoreContext
     * @param userFileList
     */
    private void doRestore(RestoreContext restoreContext, List<UserFile> userFileList) {
        List<UserFile> allNeedRestoreFile = Lists.newArrayList();

        for (UserFile userFile : userFileList) {
            if (FolderFlag.YES.getCode().equals(userFile.getFolderFlag())) {
                findAllChildFile(allNeedRestoreFile, userFile);
            }
        }
        allNeedRestoreFile.addAll(userFileList);
        allNeedRestoreFile = allNeedRestoreFile.stream().map(r -> {
            r.setDelFlag(FileDelFlag.NORMAL.getCode());
            r.setUpdateTime(new Date());
            return r;
        }).collect(Collectors.toList());
        boolean b = userFileService.updateBatchById(allNeedRestoreFile);
        if (!b) {
            throw new BusinessException("还原失败");
        }
    }

    /**
     * 找到所有需要恢复的文件，包括当前目录的子目录及其文件
     *
     * @param allNeedRestoreFile
     * @param userFile
     */
    private void findAllChildFile(List<UserFile> allNeedRestoreFile, UserFile userFile) {
        if (userFile == null || !FolderFlag.YES.getCode().equals(userFile.getFolderFlag())) {
            return;
        }
        //当点userFile目录下的所有文件
        List<UserFile> list = userFileService.list(new LambdaQueryWrapper<UserFile>()
                .eq(UserFile::getParentId, userFile.getFileId())
                .eq(UserFile::getDelFlag, FileDelFlag.RECYCLE_HIDDEN.getCode()));
        for (UserFile u : list) {
            allNeedRestoreFile.add(u);
            if (FolderFlag.YES.getCode().equals(u.getFolderFlag())) {
                findAllChildFile(allNeedRestoreFile, u);
            }
        }
    }

    /**
     * 校验恢复权限
     *
     * @param restoreContext
     * @return
     */
    private List<UserFile> checkRestorePermission(RestoreContext restoreContext) {
        List<Long> fileIds = restoreContext.getFileIds();
        Long userId = restoreContext.getUserId();
        List<UserFile> userFileList = userFileService.list(new LambdaQueryWrapper<UserFile>()
                .eq(UserFile::getUserId, userId)
                .eq(UserFile::getDelFlag, FileDelFlag.RECYCLE.getCode())
                .in(UserFile::getFileId, fileIds)
        );
        if (userFileList == null || userFileList.isEmpty()) {
            log.error("文件还原失败，文件还原非本人进行，非法操作");
            throw new BusinessException(ResponseStatus.ILLEGAL_OPERATION);
        }
        if (fileIds.size() != userFileList.size()) {
            log.error("文件还原失败，文件还原非本人进行，非法操作");
            throw new BusinessException(ResponseStatus.ILLEGAL_OPERATION);
        }
        return userFileList;
    }


}
